﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace DNX.IoCnoC
{
    public interface IConstructor
    {
        List<IParameterHandle> Parameters { get; }
        
    }

    public class Constructor : IConstructor
    {
        public Constructor()
        {
            Parameters = new List<IParameterHandle>();
        }

        public List<IParameterHandle> Parameters { get; private set; }
    }


    public interface IParameterHandle
    {
        Type Contract { get; set; }
        List<Type> Implementations { get; }
        object DefaultValue { get; set; }
        Type DefaultImplementation { get; }
    }

    public class ParameterHandle : IParameterHandle
    {
        public ParameterHandle()
        {
            Implementations = new List<Type>();
        }

        public Type Contract { get; set; }
        public List<Type> Implementations { get; private set; }
        public object DefaultValue { get; set; }

        private Type defaultImplementation;
        public Type DefaultImplementation
        {
            get
            {
                if (Contract.IsArray)
                    return null;
                
                if (defaultImplementation != null)
                    return defaultImplementation;
               
                foreach (var implementation in Implementations.Where(implementation => implementation.GetCustomAttribute(typeof (DefaultImplementationAttribute)) != null))
                {
                    defaultImplementation = implementation;
                    return defaultImplementation;
                }    
                defaultImplementation = Implementations.FirstOrDefault(i=>i.IsClass);
                return defaultImplementation;
            }
        }
    }

    [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
    public sealed class DefaultImplementationAttribute : Attribute
    {
    }


    public interface ITypeHandle
    {
        List<IConstructor> Constructors { get; }
        IConstructor Default { get; }
        ILifeStyleAction LifeStyle { get; set; }
        Type Type { get; set; }
        ITypeHandle[] Twins { get; set; }
        List<Type> Properties { get; }
        Type DefaultImplementation { get; }
    }

    public class TypeHandle : ITypeHandle
    {
        public TypeHandle()
        {
            Constructors = new List<IConstructor>();
            Properties = new List<Type>();
            Twins = new ITypeHandle[0];
            LifeStyle = new UndefinedLifeStyleAction();

        }
        public ITypeHandle[] Twins { get; set; }
        
        public Type Type { get; set; }
        public List<IConstructor> Constructors { get; private set; }
        public IConstructor Default { get; set; }
        public ILifeStyleAction LifeStyle { get; set; }
        private Type defaultImplementation;
        public List<Type> Properties  { get; private set; }

        public Type DefaultImplementation
        {
            get
            {
                if (Type.IsArray)
                    return null;

                if (defaultImplementation != null)
                    return defaultImplementation;

                foreach (var implementation in Twins.Where(implementation => implementation.Type.GetCustomAttribute(typeof(DefaultImplementationAttribute)) != null))
                {
                    defaultImplementation = implementation.Type;
                    return defaultImplementation;
                }
                var x  = Twins.FirstOrDefault(i => i.Type.IsClass);
                if (x != null)
                    defaultImplementation = x.Type;
                if (x == null)
                    defaultImplementation = Type;
                return defaultImplementation;
            }
        }
    }
   
    public interface ILifeStyleAction
    {
        void Transient(Action action);
        void Singleton(Action action);
    }

    public class UndefinedLifeStyleAction : ILifeStyleAction
    {
        public void Transient(Action action)
        {
        
        }

        public void Singleton(Action action)
        {
        }
    }

    public class TransientAction : ILifeStyleAction
    {
        public void Transient(Action action)
        {
            action();
        }

        public void Singleton(Action action)
        {
            
        }
    }

    public class SingletonAction : ILifeStyleAction
    {
        public void Transient(Action action)
        {
            
        }

        public void Singleton(Action action)
        {
            action();
        }
    }
}